using System;
using System.Diagnostics.Contracts;

namespace Charisma.Common.Disposable
{
  /// <summary>
  /// A disposable type allowing to execute custom
  /// <see cref="Action"/> on its disposal.
  /// </summary>
  public class Disposable :
    IDisposable
  {
    private readonly Action<bool> onDispose;

    /// <summary>
    /// Joins the <see cref="Disposable"/> and <see cref="IDisposable"/>.
    /// </summary>
    /// <param name="first">The first disposable to join.</param>
    /// <param name="second">The second disposable to join.</param>
    /// <returns>New <see cref="JoiningDisposable"/> that will
    /// dispose both of them on its disposal</returns>
    public static JoiningDisposable operator &(Disposable first, IDisposable second)
    {
      Contract.Requires(first != null);
      Contract.Requires(second != null);

      return new JoiningDisposable(first, second);
    }

    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
      Contract.Invariant(onDispose != null);
    }


    // Constructors

    public Disposable(Action<bool> onDispose)
    {
      Contract.Requires(onDispose != null);
      Contract.Ensures(this.onDispose != null);
      this.onDispose = onDispose;
    }


    // Destructor

    protected virtual void Dispose(bool disposing)
    {
      onDispose(disposing);
      if (!disposing)
        GC.SuppressFinalize(this);
    }

    public void Dispose()
    {
      Dispose(true);
    }
  }

}